package com.milepost.workflow.flowinsttask.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.milepost.workflow.common.dto.BootstrapTableVoDto;
import com.milepost.workflow.common.enums.PassEnum;
import com.milepost.workflow.common.enums.TaskTypeEnum;
import com.milepost.workflow.flowinst.entity.FlowInstEntity;
import com.milepost.workflow.flowinst.mapper.FlowInstMapper;
import com.milepost.workflow.flowinsttask.dto.ApproveTaskDto;
import com.milepost.workflow.flowinsttask.dto.ApprovedTaskDto;
import com.milepost.workflow.flowinsttask.entity.FlowInstTaskEntity;
import com.milepost.workflow.flowinsttask.mapper.FlowInstTaskMapper;
import com.milepost.workflow.flowinsttask.service.FlowInstTaskService;
import com.milepost.workflow.flowinsttask.vo.ApproveTaskVo;
import com.milepost.workflow.flowinsttask.vo.ApprovedTaskVo;
import com.milepost.workflow.flowinsttaskapp.entity.FlowInstTaskAppEntity;
import com.milepost.workflow.flowinsttaskapp.mapper.FlowInstTaskAppMapper;
import com.milepost.workflow.util.UUIDUtil;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

/**
 * @author huarf
 * @Description
 * @create 2022-03-28 23:45
 */
@Service
@RequiredArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class FlowInstTaskServiceImpl extends ServiceImpl<FlowInstTaskMapper, FlowInstTaskEntity> implements FlowInstTaskService {

    private final FlowInstTaskMapper flowInstTaskMapper;

    private final FlowInstTaskAppMapper flowInstTaskAppMapper;

    private final FlowInstMapper flowInstMapper;

    @Override
    public Page<ApproveTaskVo> getApproveTaskList(BootstrapTableVoDto bootstrapTableVoDto, ApproveTaskDto approveTaskDto) {

        Page<ApproveTaskVo> page = new Page<>(bootstrapTableVoDto.getPageNumber(), bootstrapTableVoDto.getPageSize());

        String sortName;
        String sortOrder;
        if (bootstrapTableVoDto.sortAvailable()) {
            sortName = bootstrapTableVoDto.getSortName();
            sortOrder = bootstrapTableVoDto.getSortOrder();
        } else {
            sortName = "taskStartTime";
            sortOrder = "desc";
        }

        Page<ApproveTaskVo> approveTaskVoPage = flowInstTaskMapper.getApproveTaskList(page, sortName, sortOrder, approveTaskDto);

        return approveTaskVoPage;
    }

    @Override
    public Boolean approveTask(FlowInstTaskAppEntity flowInstTaskAppEntity) {

        //同一个流程的审批动作需要同步
        synchronized (flowInstTaskAppEntity.getFlowInstId().intern()) {

            String flowInstId = flowInstTaskAppEntity.getFlowInstId();
            String flowInstTaskId = flowInstTaskAppEntity.getFlowInstTaskId();
            Date nowDate = new Date();

            //获取当前流程实例
            //FlowInstEntity flowInstEntity = flowInstMapper.selectById(flowInstId);
            //获取当前流程的所有任务
            List<FlowInstTaskEntity> flowInstTaskEntityList = flowInstTaskMapper.selectList(new QueryWrapper<FlowInstTaskEntity>().lambda()
                    .eq(FlowInstTaskEntity::getFlowInstId, flowInstId)
                    .orderByAsc(FlowInstTaskEntity::getOrderNum));
            //获取当前任务的所有审批记录，不包含本次审批记录
            List<FlowInstTaskAppEntity> flowInstTaskAppEntityList = flowInstTaskAppMapper.selectList(new QueryWrapper<FlowInstTaskAppEntity>().lambda()
                    .eq(FlowInstTaskAppEntity::getFlowInstTaskId, flowInstTaskId)
                    .orderByAsc(FlowInstTaskAppEntity::getEndTime));
            //获取当前任务
            FlowInstTaskEntity flowInstTaskEntity = getById(flowInstTaskId, flowInstTaskEntityList);
            //获取当前任务的下一个任务
            FlowInstTaskEntity nextFlowInstTaskEntity = getNextTask(flowInstTaskId, flowInstTaskEntityList);
            //获取end任务
            FlowInstTaskEntity endFlowInstTaskEntity = flowInstTaskEntityList.get(flowInstTaskEntityList.size()-1);

            //1、校验审批操作是否合法
            String msg = checkApprove(flowInstTaskEntity, flowInstTaskAppEntity);
            if (StringUtils.isNotBlank(msg)) {
                //非法审批。
                throw new RuntimeException(msg);
            }

            //2、插入审批记录
            flowInstTaskAppEntity.setStartTime(flowInstTaskEntity.getStartTime());
            insertFlowInstTaskAppEntity(flowInstTaskAppEntity);
            flowInstTaskAppEntityList.add(flowInstTaskAppEntity);

            //3、判断审批结果
            Integer pass = flowInstTaskAppEntity.getPass();
            if (pass == PassEnum.AGREE.getCode()) {
                //审批通过

                String taskType = flowInstTaskEntity.getType();
                //是否所有办理人都进行了审批
                boolean allAssigneeApproved = getAllAssigneeApproved(flowInstTaskAppEntityList, flowInstTaskEntity);
                if ((taskType.equalsIgnoreCase(TaskTypeEnum.AND_TASK.getType()) && allAssigneeApproved)
                        || !taskType.equalsIgnoreCase(TaskTypeEnum.AND_TASK.getType())) {
                    //(当前任务是andTask && 所有审批人都进行了审批) || 当前任务不是andTask

                    //将当前任务的pass设置成1，
                    flowInstTaskMapper.update(null, Wrappers.<FlowInstTaskEntity>lambdaUpdate()
                            .set(FlowInstTaskEntity::getPass, PassEnum.AGREE.getCode())
                            .set(FlowInstTaskEntity::getEndTime, nowDate)
                            .eq(FlowInstTaskEntity::getId, flowInstTaskId));

                    if (TaskTypeEnum.END.getType().equalsIgnoreCase(nextFlowInstTaskEntity.getType())) {
                        //下一个节点是end

                        //将下一个节点(end节点)的pass设置成1
                        flowInstTaskMapper.update(null, Wrappers.<FlowInstTaskEntity>lambdaUpdate()
                                .set(FlowInstTaskEntity::getPass, PassEnum.AGREE.getCode())
                                .set(FlowInstTaskEntity::getStartTime, nowDate)
                                .set(FlowInstTaskEntity::getEndTime, nowDate)
                                .eq(FlowInstTaskEntity::getId, nextFlowInstTaskEntity.getId()));
                        //flow_inst中end_time、curr_task_id=end节点的id、pass=1，流程结束。
                        flowInstMapper.update(null, Wrappers.<FlowInstEntity>lambdaUpdate()
                                .set(FlowInstEntity::getEndTime, nowDate)
                                .set(FlowInstEntity::getCurrTaskId, nextFlowInstTaskEntity.getId())
                                .set(FlowInstEntity::getPass, PassEnum.AGREE.getCode())
                                .eq(FlowInstEntity::getId, flowInstId));
                    } else {
                        //将下一个节点的pass设置成2
                        flowInstTaskMapper.update(null, Wrappers.<FlowInstTaskEntity>lambdaUpdate()
                                .set(FlowInstTaskEntity::getPass, PassEnum.WAITING.getCode())
                                .set(FlowInstTaskEntity::getStartTime, nowDate)
                                .eq(FlowInstTaskEntity::getId, nextFlowInstTaskEntity.getId()));

                        //将 flow_inst 中 curr_task_id 向下移动一个节点。
                        flowInstMapper.update(null, Wrappers.<FlowInstEntity>lambdaUpdate()
                                .set(FlowInstEntity::getCurrTaskId, nextFlowInstTaskEntity.getId())
                                .eq(FlowInstEntity::getId, flowInstId));
                    }
                }
            } else {
                //审批拒绝
                //将当前任务的pass设置成0，
                flowInstTaskMapper.update(null, Wrappers.<FlowInstTaskEntity>lambdaUpdate()
                        .set(FlowInstTaskEntity::getPass, PassEnum.REFUSE.getCode())
                        .set(FlowInstTaskEntity::getEndTime, nowDate)
                        .eq(FlowInstTaskEntity::getId, flowInstTaskId));

                //将当前流程的end节点的pass设置成1，
                flowInstTaskMapper.update(null, Wrappers.<FlowInstTaskEntity>lambdaUpdate()
                        .set(FlowInstTaskEntity::getStartTime, nowDate)
                        .set(FlowInstTaskEntity::getEndTime, nowDate)
                        .set(FlowInstTaskEntity::getPass, PassEnum.AGREE.getCode())
                        .eq(FlowInstTaskEntity::getId, endFlowInstTaskEntity.getId()));

                //flow_inst中end_time、curr_task_id = end节点的id、pass = 0，流程结束。
                flowInstMapper.update(null, Wrappers.<FlowInstEntity>lambdaUpdate()
                        .set(FlowInstEntity::getEndTime, nowDate)
                        .set(FlowInstEntity::getCurrTaskId, endFlowInstTaskEntity.getId())
                        .set(FlowInstEntity::getPass, PassEnum.REFUSE.getCode())
                        .eq(FlowInstEntity::getId, flowInstId));
            }
            return true;
        }
    }

    @Override
    public Page<ApprovedTaskVo> getApprovedTaskList(BootstrapTableVoDto bootstrapTableVoDto, ApprovedTaskDto approvedTaskDto) {
        Page<ApprovedTaskVo> page = new Page<>(bootstrapTableVoDto.getPageNumber(), bootstrapTableVoDto.getPageSize());

        String sortName;
        String sortOrder;
        if (bootstrapTableVoDto.sortAvailable()) {
            sortName = bootstrapTableVoDto.getSortName();
            sortOrder = bootstrapTableVoDto.getSortOrder();
        } else {
            sortName = "taskStartTime";
            sortOrder = "desc";
        }

        Page<ApprovedTaskVo> approvedTaskVoPage = flowInstTaskMapper.getApprovedTaskList(page, sortName, sortOrder, approvedTaskDto);

        return approvedTaskVoPage;
    }

    /**
     * 检验审批操作是否合法，
     *  1、一个节点同一个人只最多能审批一次
     *  2、orTask，只能有一个人审批，
     * @param flowInstTaskEntity
     * @param flowInstTaskAppEntity
     * @return
     */
    private String checkApprove(FlowInstTaskEntity flowInstTaskEntity, FlowInstTaskAppEntity flowInstTaskAppEntity) {

        Long allTaskCount = flowInstTaskAppMapper.selectCount(new QueryWrapper<FlowInstTaskAppEntity>().lambda()
                .eq(FlowInstTaskAppEntity::getFlowInstTaskId, flowInstTaskAppEntity.getFlowInstTaskId())
                .eq(FlowInstTaskAppEntity::getAssignee, flowInstTaskAppEntity.getAssignee()));
        if (allTaskCount > 0) {
            return "您已审批完成，请勿重复审批。";
        }

        if (TaskTypeEnum.OR_TASK.getType().equalsIgnoreCase(flowInstTaskEntity.getType())) {
            Long orTaskCount = flowInstTaskAppMapper.selectCount(new QueryWrapper<FlowInstTaskAppEntity>().lambda()
                    .eq(FlowInstTaskAppEntity::getFlowInstTaskId, flowInstTaskAppEntity.getFlowInstTaskId()));
            if (orTaskCount > 0) {
                return "其他用户审批完成，请忽略。";
            }
        }

        return null;
    }

    /**
     * 是否所有办理人都进行了审批
     * @param flowInstTaskAppEntityList
     * @param flowInstTaskEntity
     * @return
     */
    private boolean getAllAssigneeApproved(List<FlowInstTaskAppEntity> flowInstTaskAppEntityList,  FlowInstTaskEntity flowInstTaskEntity) {
        int totalApprove = 0;
        for (FlowInstTaskAppEntity flowInstTaskAppEntity : flowInstTaskAppEntityList) {
            if (flowInstTaskAppEntity.getFlowInstTaskId().equals(flowInstTaskEntity.getId()))  {
                totalApprove++;
            }
        }

        if (totalApprove == flowInstTaskEntity.getAssignees().split(",").length) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 通过任务id获取任务实例
     * @param flowInstTaskId
     * @param flowInstTaskEntityList
     * @return
     */
    private FlowInstTaskEntity getById(String flowInstTaskId, List<FlowInstTaskEntity> flowInstTaskEntityList) {
        for (int i = 0; i < flowInstTaskEntityList.size(); i++) {
            FlowInstTaskEntity flowInstTaskEntity = flowInstTaskEntityList.get(i);
            if (flowInstTaskId.equalsIgnoreCase(flowInstTaskEntity.getId())) {
                return flowInstTaskEntity;
            }
        }
        throw new RuntimeException("获取当前节点异常");
    }

    /**
     * 获取下一个节点的任务类型
     * @param flowInstTaskId
     * @param flowInstTaskEntityList
     * @return
     */
    private FlowInstTaskEntity getNextTask(String flowInstTaskId, List<FlowInstTaskEntity> flowInstTaskEntityList) {
        for (int i = 0; i < flowInstTaskEntityList.size(); i++) {
            FlowInstTaskEntity flowInstTaskEntity = flowInstTaskEntityList.get(i);
            if (flowInstTaskId.equalsIgnoreCase(flowInstTaskEntity.getId())) {
                return flowInstTaskEntityList.get(i+1);
            }
        }
        throw new RuntimeException("获取当前节点的下一个节点异常");
    }

    /**
     * 插入审批记录
     *
     * @param flowInstTaskAppEntity
     */
    private void insertFlowInstTaskAppEntity(FlowInstTaskAppEntity flowInstTaskAppEntity) {

        flowInstTaskAppEntity.setId(UUIDUtil.randomUUID());
        flowInstTaskAppEntity.setEndTime(new Date());
        int insert = flowInstTaskAppMapper.insert(flowInstTaskAppEntity);
        if (insert <= 0) {
            throw new RuntimeException("插入审批记录异常");
        }
    }

}
